﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Web;
using System.Reflection;


namespace SFast.Encryption
{
    public static class DesEncryption
    {
        #region _DESEnCode ECB模式的des加密，解密
        /// <summary>
        /// ECB模式的des加密
        /// (旧函数：_DESEnCode 请换成此函数)
        /// </summary>
        /// <param name="pToEncrypt"></param>
        /// <param name="sKey"></param>
        /// <returns></returns>
        public static String _DESEnCodeByECB(this String pToEncrypt, string sKey)
        {
            return _DESEnCodeByECB(pToEncrypt, sKey, Encoding.UTF8);
        }

        public static String _DESEnCodeByECB(this String pToEncrypt, string sKey, Encoding encode)
        {

            TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
            DES.Mode = CipherMode.ECB;
            DES.Padding = PaddingMode.PKCS7;
            byte[] bytes = encode.GetBytes(sKey);
            byte[] keyBytes = new byte[24];
            Array.Copy(bytes, 0, keyBytes, 0, bytes.Length >= keyBytes.Length ? keyBytes.Length : bytes.Length);

            Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");
            object obj = t.GetField("Encrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);

            MethodInfo mi = DES.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
            ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DES, new object[] { keyBytes, CipherMode.ECB, null, 0, obj });

            byte[] Buffer = encode.GetBytes(pToEncrypt);
            byte[] result = desCrypt.TransformFinalBlock(Buffer, 0, Buffer.Length);
            return Convert.ToBase64String(result);

            #region
            //pToEncrypt = HttpContext.Current.Server.UrlEncode(pToEncrypt);
            //DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            //byte[] inputByteArray = Encoding.GetEncoding("UTF-8").GetBytes(pToEncrypt);

            //des.Mode = CipherMode.ECB;
            //des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
            //des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
            //MemoryStream ms = new MemoryStream();
            //CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

            //cs.Write(inputByteArray, 0, inputByteArray.Length);
            //cs.FlushFinalBlock();

            //StringBuilder ret = new StringBuilder();
            //foreach (byte b in ms.ToArray())
            //{
            //    ret.AppendFormat("{0:X2}", b);
            //}
            //ret.ToString();
            //return ret.ToString();
            #endregion
        }

        /// <summary>
        /// ECB模式的des解密  
        /// 默认UTF-8编码
        /// (旧函数：_DESDeCode 请换成此函数)
        /// </summary>
        /// <param name="pToDecrypt">需要解密的字符串</param>
        /// <param name="sKey">解密密钥</param>
        /// <returns></returns>
        public static String _DESDeCodeByECB(this String pToEncrypt, string sKey)
        {
            return _DESDeCodeByECB(pToEncrypt, sKey, Encoding.UTF8);
        }


        /// <summary>
        /// ECB模式的des解密
        /// (旧函数：_DESDeCode 请换成此函数)
        /// </summary>
        /// <param name="pToDecrypt">需要解密的字符串</param>
        /// <param name="sKey">解密密钥</param>
        /// <param name="encode">编码方式</param>
        /// <returns></returns>
        public static String _DESDeCodeByECB(this String pToDecrypt, string sKey, Encoding encode)
        {

            TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
            DES.Mode = CipherMode.ECB;
            DES.Padding = PaddingMode.PKCS7;
            byte[] bytes = encode.GetBytes(sKey);
            byte[] keyBytes = new byte[24];
            Array.Copy(bytes, 0, keyBytes, 0, bytes.Length >= keyBytes.Length ? keyBytes.Length : bytes.Length);

            Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");
            object obj = t.GetField("Decrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);

            MethodInfo mi = DES.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
            ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DES, new object[] { keyBytes, CipherMode.ECB, null, 0, obj });

            byte[] Buffer = Convert.FromBase64String(pToDecrypt);
            byte[] result = desCrypt.TransformFinalBlock(Buffer, 0, Buffer.Length);
            return encode.GetString(result);

            //DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            //byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
            //for (int x = 0; x < pToDecrypt.Length / 2; x++)
            //{
            //    int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
            //    inputByteArray[x] = (byte)i;
            //}
            //des.Mode = CipherMode.ECB;
            //des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
            //des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
            //MemoryStream ms = new MemoryStream();
            //CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            //cs.Write(inputByteArray, 0, inputByteArray.Length);
            //cs.FlushFinalBlock();

            //StringBuilder ret = new StringBuilder();

            //return HttpContext.Current.Server.UrlDecode(System.Text.Encoding.Default.GetString(ms.ToArray()));
        }

        #endregion

        #region CBC模式，对字符串的des加密（可选是否转换16进制）

        /// <summary>
        /// CBC模式的des加密
        /// 默认：UTF-8转换格式 ，返回16进制的密文
        /// </summary>
        /// <param name="sourceString">要加密的原文</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string _DesEncodeByCBC(this String sourceString, String key)
        {
            return _DesEncodeByCBC(sourceString, key, Encoding.UTF8, true);
        }

        /// <summary>
        /// CBC模式的des加密
        /// </summary>
        /// <param name="sourceString">要加密的原文</param>
        /// <param name="key">密钥</param>
        /// <param name="encode">制定转换时的编码格式</param>
        /// <param name="toHex">是否把密文转换成16进制</param>
        /// <returns></returns>
        public static string _DesEncodeByCBC(this String sourceString, String key, Encoding encode, bool toHex)
        {
            byte[] btKey = encode.GetBytes(key);
            byte[] btIV = encode.GetBytes(key);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            byte[] inData = encode.GetBytes(sourceString);
            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write))
                    {
                        cs.Write(inData, 0, inData.Length);
                        cs.FlushFinalBlock();
                    }
                    byte[] btcode = ms.ToArray();
                    if (toHex)  //如果需要转16进制
                    {
                        return btcode._ToHaxString();
                    }
                    else
                    {
                        return encode.GetString(btcode);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// CBC模式的des解密
        /// 默认：UTF-8转换格式 ，对16进制的密文进行解密
        /// </summary>
        /// <param name="encryptedString">16进制的密文</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string _DesDecodeByCBC(this String encryptedString, String key)
        {
            return _DesDecodeByCBC(encryptedString, key, Encoding.UTF8, true);
        }
        
        /// <summary>
        /// CBC模式的des解密
        /// </summary>
        /// <param name="encryptedString">要解密的密文</param>
        /// <param name="key">密钥</param>
        /// <param name="encode">编码方式</param>
        /// <param name="toHex">是否对密文进16进制 to byte[] 的转码</param>
        /// <returns></returns>
        public static string _DesDecodeByCBC(this String encryptedString, String key, Encoding encode, bool toHex)
        {
            var inData = encode.GetBytes(encryptedString);
            if (toHex)
            {
                inData = encryptedString._HexToBytes(); //16进制转换byte[]类型
            }

            byte[] btKey = encode.GetBytes(key);
            byte[] btIV = encode.GetBytes(key);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(btKey, btIV), CryptoStreamMode.Write))
                    {
                        cs.Write(inData, 0, inData.Length);
                        cs.FlushFinalBlock();
                    }
                    return encode.GetString(ms.ToArray());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
        #endregion


        #region 对文件加密
        /// <summary>
        /// 对文件内容进行DES加密
        /// </summary>
        /// <param name="sourceFile">待加密的文件绝对路径</param>
        /// <param name="destFile">加密后的文件保存的绝对路径</param>
        public static void _DESDeCodeFileByCBC(String sourceFile, String destFile, String key)
        {
            if (!File.Exists(sourceFile)) throw new FileNotFoundException("指定的文件路径不存在！", sourceFile);


            byte[] btKey = Encoding.Default.GetBytes(key);
            byte[] btIV = Encoding.Default.GetBytes(key);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            byte[] btFile = File.ReadAllBytes(sourceFile);


            using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write))
            {
                try
                {
                    using (CryptoStream cs = new CryptoStream(fs, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write))
                    {
                        cs.Write(btFile, 0, btFile.Length);
                        cs.FlushFinalBlock();
                    }
                }
                catch
                {
                    throw;
                }
                finally
                {
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// 对文件内容进行DES加密，加密后覆盖掉原来的文件
        /// </summary>
        /// <param name="sourceFile">待加密的文件的绝对路径</param>
        public static void _DESDeCodeFileByCBC(String sourceFile, String key)
        {
            _DESDeCodeFileByCBC(sourceFile, sourceFile, key);
        }
        #endregion


    }
}

